#ifdef __linux__
# ifndef _GNU_SOURCE
#  define _GNU_SOURCE
# endif
# include <execinfo.h>
# include <cxxabi.h>
# include <alloca.h>
# define BACKTRACE_MAXSIZE 100
#endif

#include <string>

#include <Common/Debug.hh>
#include <Common/Logging.hh>

namespace Common
{
namespace Debug
{

std::string demangle( const char *name )
{
#ifdef __linux__
	char *tmp = abi::__cxa_demangle( name, NULL, NULL, NULL );

	std::string demangled( tmp );

	free( tmp );

	return demangled;
#else
#error "Not implemented!"
#endif
}

void logBacktrace( int start, int end )
{
#ifdef __linux__
	void **buffer = (void **)alloca( BACKTRACE_MAXSIZE * sizeof( void* ) );

	L_ << "Backtrace:";

	int nptrs = backtrace( buffer, BACKTRACE_MAXSIZE );

	for ( int j = start; j < nptrs + end; j++ )
	{
		L_ << " " << j + 1 - start << ": " << buffer[j];
	}
#else
#error "Not implemented!"
#endif
}

AssertionException::AssertionException( char const *expr, char const *function, char const *file, long line ) throw()
{
	std::stringstream stream;

	stream << file << ":" << line << ":" << function << ": assert( " << expr << " ) failed!";

	desc = stream.str();

	L_ << desc;

	Common::Debug::logBacktrace( 3, -3 );
}

}

}

void boost::assertion_failed( char const *expr, char const *function, char const *file, long line )
{
	const char *basename = strrchr( file, '/' );

	if ( basename )
		file = basename + 1;

	throw Common::Debug::AssertionException( expr, function, file, line );
}
